/*
 * ValueImpl.hpp 
 * create 2009-11-20
 * by ws
 */
#ifndef VALUEIMPL_HPP
#define VALUEIMPL_HPP
#include"common.hpp"
#include"RegMask.hpp"
#include"MachineSpec.hpp"


enum VType{
	//for abstract memory object
	MEM_VT = 0x0001,
	//for register
	REG_VT = 0x0006,
	GEN_VT = 0x0002,
	MACRO_VT = 0x0004,
	CONST_VT = 0x0038,
	LABEL_VT = 0x0008,
	IMM_VT = 0x0010,
	BB_VT = 0x0020,
	//for ctr flow
	CTR_FLOW_VT = 0x00020
};

class Value{
protected:
	Value(int id, enum VType vt):id(id), vt(vt)
	{ }
	enum VType vt;
	int id;
public:
	bool isa(enum VType vt)
	{
		return vt & this->vt;
	}
	enum VType get_type()const
	{
		return vt;
	}
	int get_id(){return id;}
	friend bool operator == (const Value & x, const Value & y);
};

class DUChain;

class RegValue:public Value{
protected:
	DUChain * du_chain;// this is build by the region::build_du_chain
	bool allocated_flag;
	enum Core core;
	RegValue(int id, enum Core c): Value(id, REG_VT), core(c), allocated_flag(false)
	{
		;
	}
public:
	
	virtual enum TargetInfo::PhysicalRegister  get_allocated_physical_register() const = 0;
	virtual void  assign_physical_register(enum TargetInfo::PhysicalRegister physical_register ) = 0;
	void build_du_chain(DUChain * chain) ;
	DUChain* get_du_chain(){return du_chain;}
	
	enum Core get_core()
	{
		return core;
	}
	bool is_allocated()
	{
		return allocated_flag;
	}
	void set_allocated()
	{
		allocated_flag = true;
	}
	
	
	friend RegValue* RegValue_cast(Value* value);
	friend const RegValue* RegValue_cast(const Value* value);
	friend bool operator == (const Value & x, const Value & y);
};

RegValue* RegValue_cast(Value*);
const RegValue* RegValue_cast(const Value* value);

class GenValue:public RegValue{
private:
	enum TargetInfo::PhysicalRegister physical_register;
public:
	enum Core get_core()
	{
		return core;
	}
	void set_cluster(enum Core core){ this->core = core;}
	enum Core get_cluster(){ return core;}
	void assign_physical_register(enum TargetInfo::PhysicalRegister physical_register);
	enum TargetInfo::PhysicalRegister  get_allocated_physical_register() const
	{
		return this->physical_register;
	}
	GenValue(int id, enum Core core = NO_CORE): RegValue(id, core)
	{
		
	}
	friend bool operator == (const Value & x, const Value & y);
	friend GenValue* GenValue_cast(Value* RegValue);
	friend const GenValue* GenValue_cast(const Value* RegValue);
};

GenValue* GenValue_cast(Value* regvalue);
const GenValue* GenValue_cast(const Value* regvalue);

class MacroValue: public RegValue{
public:
	MacroValue(enum MACRO_ID id):RegValue(id, M_get_macro_core(id))
	{
		;
	}
	enum TargetInfo::PhysicalRegister get_allocated_physical_register() const
	{
		return M_get_macro_physical_register((enum MACRO_ID )id);
	}
	void assign_physical_register(enum TargetInfo::PhysicalRegister physical_register);

	friend MacroValue * MacroValue_cast(Value* regvalue);
	friend const MacroValue * MacroValue_cast(const Value* regvalue);
	friend bool operator == (const Value & x, const Value & y);
};

MacroValue * MacroValue_cast(Value * regvalue);
const MacroValue * MacroValue_cast(const Value * regvalue);

class ConstValue:public Value{
	friend ConstValue * ConstValue_cast(Value * value);
	enum VType const_type;
protected:
	ConstValue(enum VType  vtype):Value(-1, CONST_VT), const_type(vtype)
	{
		;
	}
	friend bool operator == (const Value & x, const Value & y);
};

class ImmValue:public ConstValue{
	int i;
public:
	ImmValue(int constant): i(constant),ConstValue(IMM_VT)
	{
	}
	friend ImmValue* ImmValue_cast(Value* constvalue);
	friend const ImmValue* ImmValue_cast(const Value* constvalue);
	friend bool operator == (const Value & x, const Value & y);
};

ImmValue* ImmValue_cast( Value * value);
const ImmValue* ImmValue_cast( const Value * value);

class LabelValue:public ConstValue{
	std::string name;
public:
	LabelValue(std::string name): ConstValue(LABEL_VT),name(name)
	{ }
	friend LabelValue* LabelValue_cast(Value * value);
	friend const LabelValue* LabelValue_cast(const Value * value);
	friend bool operator == (const Value & x, const Value & y);
};
extern LabelValue* LabelValue_cast(Value*);
extern const LabelValue* LabelValue_cast(const Value*);

class Region;
class BBValue:public ConstValue{
	Region *bb;
	BBValue(Region * bb): ConstValue(BB_VT), bb(bb)
	{ }
	friend BBValue * BBValue_cast(Value* v);
	friend const BBValue * BBValue_cast(const Value * v);
	friend bool operator == (const Value & x, const Value & y);
};
extern BBValue * BBValue_cast(Value*);
extern const LabelValue * LabelValue_cast(const Value * v);

class CtrFlowValue:public Value{
public:
	CtrFlowValue():Value(-1, CTR_FLOW_VT)
	{ }
	friend CtrFlowValue* CtrFlowValue_cast(Value * value);
	friend const CtrFlowValue* CtrFlowValue_cast(const Value * value);
	friend bool operator == (const Value & x, const Value & y);
};

CtrFlowValue * CtrFlowValue_cast(Value * v);
const CtrFlowValue * CtrFlowValue_cast(const Value * v);

class MemValue:public Value{
public:
	MemValue():Value(-1, MEM_VT)
	{ }
	friend MemValue* MemValue_cast(Value *);
	friend const MemValue* MemValue_cast(const Value *);
	friend bool operator == (const Value & x, const Value & y);
};
MemValue* MemValue_cast(Value* v);
const MemValue* MemValue_cast(const Value* v);

bool operator == (const Value & x, const Value & y);
bool operator != (const Value &x, const Value &y);

#endif
